from copy import copy
import logging

from mythril.analysis.module.base import DetectionModule, EntryPoint
from mythril.analysis.report import Issue
from mythril.laser.ethereum.state.constraints import Constraints
from mythril.laser.smt import symbol_factory, UGT, BitVec, Or
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.state.annotation import StateAnnotation
from mythril.analysis import solver
from mythril.exceptions import UnsatError
from typing import List, cast, Optional
from copy import copy
from mythril.analysis.module.module_helpers import is_prehook
from mythril.laser.ethereum.state.global_state import GlobalState
from mythril.laser.ethereum.state.annotation import StateAnnotation

from mythril.analysis.swc_data import TX_ORDER_DEPENDENCE

from typing import cast, List
import re



"""
class TransactionOrderAnnotation(StateAnnotation):
    def __init__(self) -> None:
        self.call_offsets = []  # type: List[int]

    def __copy__(self):
        result = TransactionOrderAnnotation()
        result.call_offsets = copy(self.call_offsets)
        return result
"""
class TransactionOrderAnnotation(StateAnnotation):
    """Symbol annotation added to a variable that is initialized with a call to the ORIGIN instruction.
        符号注释添加到变量中，该变量通过调用origin指令初始化。
    """

    def __init__(self, call_state: GlobalState) -> None:
        self.call_state = call_state
        self.state_change_states = []  # type: List[GlobalState]
        

    def __copy__(self):
        new_annotation = TransactionOrderAnnotation(
            self.call_state
        )
        new_annotation.state_change_states = self.state_change_states[:]
        return new_annotation

class TransactionOrder(DetectionModule):
    """This module checks for Transaction Order ."""

    name = "TransactionOrder"
    swc_id = TX_ORDER_DEPENDENCE
    description = "Check for TransactionOrder"
    entry_point = EntryPoint.CALLBACK
    pre_hooks = ["CALL", "DELEGATECALL", "SSTORE"]

    def _execute(self, state: GlobalState) -> None:
        #print("Aaaaaaaaaaaaaaaaaa")
        if state.get_current_instruction()["address"] in self.cache:
            return
        issues = self._analyze_state(state)
        for issue in issues:
            self.cache.add(issue.address)
        self.issues.extend(issues)

    @staticmethod
    def _analyze_state(state: GlobalState):         
        """
        :param state: the current state
        :return: returns the issues for that corresponding state
        """
        instruction = state.get_current_instruction()

        annotations = cast(
            List[TransactionOrderAnnotation],
            list(state.get_annotations(TransactionOrderAnnotation)),
        )
        #if len(annotations) == 0:
            # state.annotate(TransactionOrderAnnotation())
            # annotations = cast(
            #     List[TransactionOrderAnnotation],
            #     list(state.get_annotations(TransactionOrderAnnotation)),
            # )
        #    return []
        

        if instruction["opcode"] in ["CALL", "DELEGATECALL"]:

            #print("bbbbbbbbbbbbbb")

            addr=state.mstate.stack[-2]
            value=state.mstate.stack[-3]
            """
            if re.match(r'storage_[a-z0-9_&^]*[0-9]+',addr):
                for annotation in annotations:
                    annotation.state_change_states.append(state)
            if re.match(r'storage_[a-z0-9_&^]*[0-9]+',value):   
                for annotation in annotations:
                    annotation.state_change_states.append(state)
            """

            if addr.symbolic:
                state.annotate(TransactionOrderAnnotation(state))
            if value.symbolic:
                state.annotate(TransactionOrderAnnotation(state))



            """
            index=0
            storage_content=None
            sol=solver()
            CanChangeStorage=[]
            for storage in storages:
                index=re.search(r'[0-9]+',storage).group()
                storage_content=

            """
        else:  # SSTORE

            for annotation in annotations:
                
                #print("aaaaaaaaaaaaaaaaaaaaaaaaaa")
                
                constraints = copy(state.world_state.constraints)     
                try:
                    transaction_sequence = solver.get_transaction_sequence(
                        state, constraints
                    )
                except UnsatError:
                    continue
                description_tail = (
                    "TransactionOrderaaaaaaaaaaaaaaaaaaaaaaaaa "
                    
                )

                issue = Issue(
                    contract=state.environment.active_account.contract_name,
                    function_name=state.environment.active_function_name,
                    address=state.get_current_instruction()["address"],
                    swc_id=TX_ORDER_DEPENDENCE,
                    bytecode=state.environment.code.bytecode,
                    title="TransactionOrderaaaaaaaaaaaaaaaaaaaaaaaaa",
                    severity="Low",
                    description_head="TransactionOrderaaaaaaaaaaaaaaaaaaaaaaaaa",
                    description_tail=description_tail,
                    gas_used=(state.mstate.min_gas_used, state.mstate.max_gas_used),
                    transaction_sequence=transaction_sequence,
                )

                return [issue]

        return []




detector = TransactionOrder()